package com.da.mybatis.interceptor;

import java.sql.Connection;
import java.util.Properties;

import com.da.mybatis.util.PermissionUtils;
import com.da.mybatis.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

/**
 * @author JokerDa.
 * @date 2020/12/25 15:01
 * Description:
 */
@Intercepts({
    @Signature(type = Executor.class, method = "query", args = {
        MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
    }), @Signature(type = StatementHandler.class, method = "prepare", args = {
    Connection.class, Integer.class})
})
@Slf4j
@Component
public class SqlIntercept implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (invocation.getTarget() instanceof RoutingStatementHandler) {
            RoutingStatementHandler handler = (RoutingStatementHandler)invocation.getTarget();
            StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(handler, "delegate");
            //通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
            MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement");
            BoundSql boundSql = delegate.getBoundSql();
            ReflectUtil.setFieldValue(boundSql, "sql", permissionSql(boundSql.getSql(), mappedStatement));
        }
        return invocation.proceed();
    }

    /**
     * 权限sql包装，以及是否需要包装
     *
     * @param sql
     * @return
     */
    protected String permissionSql(String sql, MappedStatement mappedStatement) {
        UserPermissionAop permissionAop = PermissionUtils.getPermissionByDelegate(mappedStatement);
        StringBuilder sbSql = new StringBuilder(sql);
        if (permissionAop != null) {
            String id = mappedStatement.getId();
            String methodName = id.substring(id.lastIndexOf(".") + 1, id.length());
            //方法过滤,待讨论
            if (methodName.equals("queryAll")) {
                return getAppendSql(sbSql, methodName);
            }
        }
        return sbSql.toString();
    }

    /**
     * sql拼接
     *
     * @param sbSql
     * @param methodName
     * @return
     */
    public String getAppendSql(StringBuilder sbSql, String methodName) {
        sbSql.append(" where student.id = 1");
        return sbSql.toString();
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {

    }
}